// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

module lvds_mm_ctrl
    #(
        parameter MASTER        =  1,
        parameter DATA_WIDTH    = 32,
        parameter ADDR_WIDTH    = 16,
        parameter TIMEOUT_PARAM = 25000
    ) 
(
    input                        clk,
    input                        reset,
    
    //memory interface connected to lvds_mm_slave module
    input                        mem_slv_write_req,
    input                        mem_slv_read_req,   
    output                       mem_slv_write_cmpl,   
    input  [ADDR_WIDTH-1:0]      mem_slv_address,
    input  [DATA_WIDTH-1:0]      mem_slv_writedata,
    output [DATA_WIDTH-1:0]      mem_slv_readdata,
    output                       mem_slv_readdatavalid,

    //Master Agent interface, Only exist on slave side
    output [ADDR_WIDTH-1:0]      mstr_agent_address,
    output                       mstr_agent_read,
    output                       mstr_agent_write,
    output [DATA_WIDTH-1:0]      mstr_agent_writedata,
    output [(DATA_WIDTH/8)-1:0]  mstr_agent_byteenable,
    input  [DATA_WIDTH-1:0]      mstr_agent_readdata,
    input                        mstr_agent_readdatavalid,
    input                        mstr_agent_waitrequest,    
     
    //Encoding AVMM events to ioc frame
    output      [7:0]            ioc_frame_o,
    input       [7:0]            ioc_frame_i,
    //tx/rx frame cnt
    input       [3:0]            tx_frm_offset,
    input       [3:0]            rx_frm_offset,
    //input from channel_ctrl
    input                        frame_loss_crc_A2H,
    input                        frame_aligned_tx,
    input                        frame_loss_crc_H2A,

    //sideband signal/reg at ioc_master side
    output      [3:0]            status_reg,
    output                       avmm_timeout,
    output      [31:0]           timeout_cnt,      //Record how many timeout event has been happened
    output                       crc_check_pass,   //1'b1: Pass; 1'b0: Fail.
    output      [31:0]           crc_err_cnt,      //Record how many crc_error has been happened
    output                       unexpected_cmpl,
    output      [31:0]           unexpected_cmpl_cnt,
    input                        invalid_access_cpu,             //Only exist on agent side, input to MM SM         
    input                        invalid_access_dbg              //Only exist on agent side, input to MM SM

);

generate 
    if (MASTER) begin:gen_slave_sm
    
        //Step1: instantiate slave SM
        lvds_mm_sm_host
            #(
                .DATA_WIDTH    (DATA_WIDTH),
                .ADDR_WIDTH    (ADDR_WIDTH),
                .TIMEOUT_PARAM (TIMEOUT_PARAM)
            )
        lvds_mm_sm_host_inst
        (
            .clk                 ( clk                           ),
            .reset               ( reset                         ),
            //memory interface                                   
            .mem_write_req       ( mem_slv_write_req             ),
            .mem_read_req        ( mem_slv_read_req              ),    
            .mem_write_cmpl      ( mem_slv_write_cmpl            ),   
            .mem_address         ( mem_slv_address               ),
            .mem_writedata       ( mem_slv_writedata             ),
            .mem_readdata        ( mem_slv_readdata              ), 
            .mem_readdatavalid   ( mem_slv_readdatavalid         ),
            //AVMM encoded events                                
            .ioc_frame_o         ( ioc_frame_o                   ),
            .ioc_frame_i         ( ioc_frame_i                   ),
            //tx/rx frame cnt
            .tx_frm_offset       ( tx_frm_offset                 ),
            .rx_frm_offset       ( rx_frm_offset                 ),
            //input from lvds_channel_ctrl
            .frame_loss_crc_A2H  ( frame_loss_crc_A2H            ),            
            .frame_aligned_tx    ( frame_aligned_tx              ),
            .frame_loss_crc_H2A  ( frame_loss_crc_H2A            ),
            //SB signals
            .status_reg          ( status_reg                    ),
            .avmm_timeout        ( avmm_timeout                  ),
            .timeout_cnt         ( timeout_cnt                   ),      
            .crc_check_pass      ( crc_check_pass                ),   
            .crc_err_cnt         ( crc_err_cnt                   ),      
            .unexpected_cmpl     ( unexpected_cmpl               ),
            .unexpected_cmpl_cnt ( unexpected_cmpl_cnt           )    
        );
        //Step2: set default value for outputs
            assign mstr_agent_address    = 'b0;
            assign mstr_agent_read       = 'b0;
            assign mstr_agent_write      = 'b0;
            assign mstr_agent_writedata  = 'b0;
            assign mstr_agent_byteenable = 'b0;
        
    end else begin:gen_master_sm
        //Step1: instantiate master SM
        lvds_mm_sm_agent
            #(
                .DATA_WIDTH    (DATA_WIDTH),
                .ADDR_WIDTH    (ADDR_WIDTH),
                .TIMEOUT_PARAM (TIMEOUT_PARAM)            
            )
        lvds_mm_sm_agent_inst
        (
            .clk                      ( clk                       ),
            .reset                    ( reset                     ), 
            //Master Agent interface, Only exist on slave side    
            .mstr_agent_address       ( mstr_agent_address        ),
            .mstr_agent_read          ( mstr_agent_read           ),
            .mstr_agent_write         ( mstr_agent_write          ),
            .mstr_agent_writedata     ( mstr_agent_writedata      ),
            .mstr_agent_byteenable    ( mstr_agent_byteenable     ),
            .mstr_agent_readdata      ( mstr_agent_readdata       ),
            .mstr_agent_readdatavalid ( mstr_agent_readdatavalid  ),
            .mstr_agent_waitrequest   ( mstr_agent_waitrequest    ),    
            //AVMM encoded events                                 
            .ioc_frame_o              ( ioc_frame_o               ),
            .ioc_frame_i              ( ioc_frame_i               ),
            //tx/rx frame cnt
            .tx_frm_offset            ( tx_frm_offset             ),
            .rx_frm_offset            ( rx_frm_offset             ), 
            //input from lvds_channel_ctrl
            .frame_loss_crc_A2H       ( frame_loss_crc_A2H        ),            
            .frame_aligned_tx         ( frame_aligned_tx          ),
            .frame_loss_crc_H2A       ( frame_loss_crc_H2A        ),
            //input from AVMM slave -- CPU/Debug FPGA CSRs
            .invalid_access_cpu       ( invalid_access_cpu        ),
            .invalid_access_dbg       ( invalid_access_dbg        ),				
            //SB signals
            .status_reg               (                           ),
            .avmm_timeout             ( avmm_timeout              ),
            .crc_check_pass           ( crc_check_pass            ),
            .crc_err_cnt              ( crc_err_cnt               ),      
            .timeout_cnt              ( timeout_cnt               )            
        );
        
        //Step2: set default value for outputs
        assign mem_slv_write_cmpl          = 'b0;
        assign mem_slv_readdata            = 'b0;
        assign mem_slv_readdatavalid       = 'b0;
        assign unexpected_cmpl             = 'b0;
        assign unexpected_cmpl_cnt         = 'b0;            
    end
endgenerate

endmodule
